package model;

import java.awt.Color;
import java.awt.geom.*;
import java.util.*;
import java.util.Vector;

import javax.swing.table.DefaultTableModel;
import org.jfree.chart.*;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.xy.*;
import org.jfree.data.xy.*;

public class Model {
	private ArrayList<Iteration> results;
	private Input input;
	
	public Model(){
		results = new ArrayList<Iteration>();	
	}
	
	public void setInput(Input input) {			this.input = input;	}
	
	public Input getInput(){					return input;		}
	public ArrayList<Iteration> getResults(){	return results;		}
	
	public void solve(){
		Point2D.Double point1 = new Point2D.Double(input.getX1(), input.getPolynomial().evaluate(input.getX1()));
		Point2D.Double point2 = new Point2D.Double(input.getX2(), input.getPolynomial().evaluate(input.getX2()));
		
		if(input.getMethod() == Input.REGULA_FALSI_METHOD)
			results = RegulaFalsi.approximate(input.getPolynomial(), point1, point2, input.getMaxIterations(), input.getTolerance());
		else
			results = Secant.approximate(input.getPolynomial(), point1, point2, input.getMaxIterations(), input.getTolerance());
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public DefaultTableModel getTableModel(){
		if(results.size() == 0)
			return new DefaultTableModel();
		
		DefaultTableModel dtm = new DefaultTableModel();
	
		dtm.addColumn("i");
		dtm.addColumn("Xi");
		dtm.addColumn("Yi");
		dtm.addColumn("Xi + 1");
		dtm.addColumn("Yi + 1");
		dtm.addColumn("Xi + 2");
		
		for(int i = 0; i < results.size();){
			Iteration ite = results.get(i);
			
			Vector row = new Vector();
			
			row.add(++i);
			row.add(ite.getPoint1().getX());
			row.add(ite.getPoint1().getY());
			row.add(ite.getPoint2().getX());
			row.add(ite.getPoint2().getY());
			row.add(ite.getNewPoint().getX());
			
			dtm.addRow(row);
		}
		return dtm;
	}
	
	public JFreeChart getXChart(){
		JFreeChart jfc = ChartFactory.createXYLineChart( "",	"i", "x", null,
				PlotOrientation.VERTICAL, true,	true,	false );

		if(results.size() == 0)
			return null;
		
		XYSeriesCollection dataset = new XYSeriesCollection();
		
		if(input.getMethod() == Input.SECANT_METHOD){
			XYSeries series1 = new XYSeries("xi");
			
			int i;
			for(i = 0; i < results.size(); ++i){
				series1.add(i+1, results.get(i).getPoint1().getX());
			}
			--i;
			series1.add(i+2, results.get(i).getPoint2().getX());
			series1.add(i+3, results.get(i).getNewPoint().getX());

			dataset.addSeries(series1);
		}
		else{
			XYSeries series1 = new XYSeries("xi");
			XYSeries series2 = new XYSeries("xi + 1");
			
			for(int i = 0; i < results.size(); ++i){
				series1.add(i+1, results.get(i).getPoint1().getX());
				series2.add(i+1, results.get(i).getPoint2().getX());
			}
			dataset.addSeries(series1);
			dataset.addSeries(series2);
		}
		jfc.getXYPlot().setDataset(dataset);

		return jfc;
	}
	
	public ArrayList<JFreeChart> getCharts(){
		if(results.size() == 0)
			return new ArrayList<JFreeChart>();
		
		ArrayList<JFreeChart> charts = new ArrayList<JFreeChart>();
		
		XYSeries polySeries = new XYSeries("polynomial");
		
		double xn = Double.NEGATIVE_INFINITY;
		double x0 = Double.POSITIVE_INFINITY;
		
		for (Iteration ite : results){
			if(ite.getPoint1().getX() > xn)
				xn = ite.getPoint1().getX();
			if(ite.getPoint2().getX() > xn)
				xn = ite.getPoint2().getX();
			if(ite.getNewPoint().getX() > xn)
				xn = ite.getNewPoint().getX();
			if(ite.getPoint1().getX() < x0)
				x0 = ite.getPoint1().getX();
			if(ite.getPoint2().getX() < x0)
				x0 = ite.getPoint2().getX();
			if(ite.getNewPoint().getX() < x0)
				x0 = ite.getNewPoint().getX();
		}
		
		double range = Math.abs(xn - x0);
		double inc = range / 50;
		double LB = x0 - range / 3;
		double UB = xn + range / 3;

		for(double i = LB; i <= UB; i += inc)
			polySeries.add(i, input.getPolynomial().evaluate(i));
		
		XYSeriesCollection dataset = new XYSeriesCollection();
		dataset.addSeries(polySeries);
		 	 
		JFreeChart chart = ChartFactory.createXYLineChart( "",	"x", "f(x)", dataset,
					PlotOrientation.VERTICAL, true,	true,	false);
		
		charts.add(chart);
		
		XYSeriesCollection iteDataset = null;
		
		for(Iteration ite : results){
			iteDataset = new XYSeriesCollection();
			
			chart = ChartFactory.createXYLineChart( "",	"x", "f(x)", null,	
					PlotOrientation.VERTICAL, true,	true, false);
			
			XYSeries iteSeries = new XYSeries("given points");
			XYSeries newPointSeries = new XYSeries("new point");
	
			iteSeries.add(ite.getPoint1().getX(), ite.getPoint1().getY());
			iteSeries.add(ite.getPoint2().getX(), ite.getPoint2().getY());			
			iteSeries.add(ite.getNewPoint().getX(), 0);
			newPointSeries.add(ite.getNewPoint().getX(), 0);
			
			iteDataset.addSeries(newPointSeries);
			iteDataset.addSeries(iteSeries);

			chart.getXYPlot().setDataset(0, iteDataset);
			chart.getXYPlot().setDataset(1, dataset);
			
			XYLineAndShapeRenderer renderer0 = new XYLineAndShapeRenderer();
		    renderer0.setBaseShapesVisible(true);
		    renderer0.setSeriesPaint(0, Color.GREEN);
		    renderer0.setSeriesShape(0, new Ellipse2D.Double(-3, -3, 6, 6));
		    renderer0.setSeriesPaint(1, Color.BLUE);
		    renderer0.setSeriesShape(1, new Ellipse2D.Double(-3, -3, 6, 6));
		    
		    XYSplineRenderer renderer1 = new XYSplineRenderer();
		    renderer1.setBaseShapesVisible(false);
		    renderer1.setSeriesPaint(0, Color.RED);
		    
			chart.getXYPlot().setRenderer(0, renderer0);
			chart.getXYPlot().setRenderer(1, renderer1);
			
			charts.add(chart);
		}
		return charts;
	}
}